/**
  CNOK project, Anyang Normal University, IMP-CAS
  \class TAHist
  \brief a local histogram class for ROOT TH1F class. But as this class only
  serves for TAConvolve's random sampling, it does not have a visualization
  function.
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2022/12/03
  \date Last modified: 2022/12/03 by SUN Yazhou
  \copyright 2020-2023 SUN Yazhou
  \copyright CNOK project, Anyang Normal University, IMP-CAS
*/

#include <algorithm>
#include <iostream>
#include <iomanip>
#include "config.h"
#include "TAException.h"

using std::swap;
using std::cout;
using std::endl;
using std::setw;
using std::ios_base;

template<class T>
TAHist<T>::TAHist(const string &name, const string &title, int nbins, double xmin, double xmax)
    : fName(name), fTitle(title){
  if(nbins <= 0) TAException::Error("TAHist", "ctor: illegal nbins: %d", nbins);
  if(xmin == xmax) TAException::Error("TAHist", "ctor: xmin == xmax occured.");
  if(xmin > xmax) swap(xmin, xmax);
  fMax = xmax; fMin = xmin; fNBins = nbins;
  fdx = (fMax-fMin)/fNBins;
  for(int i = 0; i <= fNBins+1; i++) fMap[i] = 0;
} // end ctor

template<class T>
TAHist<T>::~TAHist(){}

// fill the histogram
template<class T>
void TAHist<T>::Fill(double v){
  if(v < fMin){ fMap[0]++; return; }
  if(v >= fMax){ fMap[fNBins+1]++; return; }

  // fMap[(v-fMin) / fdx +1]++;
  fMap[int((v-fMin)/fdx)+1]++;
} // end member function Fill

// \param i: bin id, starts from 1, ends at fNBins
template<class T>
T TAHist<T>::GetBinContent(int i) const{
  if(i < 0 || i > fNBins+1) TAException::Error("TAHist",
    "GetBinContent: required bin id %d out of range", i);
  return fMap.at(i);
} // end member function GetBinContent

// \param i: bin id, starts from 1, ends at fNBins
template<class T>
double TAHist<T>::GetBinCenter(int i) const{
  if(i <= 0 || i > fNBins) TAException::Error("TAHist",
    "GetBinCenter: required bin id %d out of range", i);
  return fMin + (i-0.5)*fdx;
} // end member function GetBinCenter


template<class T>
void TAHist<T>::Scale(double v){
  for(auto &p : fMap) p.second *= v;
} // end member function Scale

// By default the integral is computed as the sum of bin contents
// in the range. if option "width" is specified, the integral is
// the sum of the bin contents multiplied by the bin width in x.
template<class T>
double TAHist<T>::Integral(const string &opt) const{
  double s = 0.;
  for(const auto &p : fMap) s += p.second;
  if("width" == opt) return s*fdx;
  return s;
} // end member function Integral

// print in a terminal in ascii characters
template<class T>
void TAHist<T>::Print() const{
  ios_base::fmtflags initial;
	initial = cout.setf(ios_base::fixed, ios_base::floatfield);
	cout.precision(2); // 15 3
	cout.unsetf(ios_base::fixed);

  cout << "Histogram " << GetName() << ": " << GetTitle() << endl;
  for(int i = 1; i <= fNBins; i++){
    cout << setw(3) << i << setw(7) << GetBinCenter(i);
    cout << ": " << string(GetBinContent(i), '*');
    cout << endl;
  } // end for over i
  cout.setf(initial);
} // end member function Print
